package com.iwdnb.gkgz.application.strategy;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import cn.hutool.core.date.DateUtil;
import com.iwdnb.gkgz.application.model.request.AddStrategyTradeStockDataRequest;
import com.iwdnb.gkgz.application.utils.RedGreenLightUtils;
import com.iwdnb.gkgz.common.enums.RangeTypeEnums;
import com.iwdnb.gkgz.common.model.dto.StockDayData;
import com.iwdnb.gkgz.common.model.dto.StrategyTradeDTO;
import com.iwdnb.gkgz.common.quota.BollingerBands;
import com.iwdnb.gkgz.common.quota.BollingerBands.BollingerData;
import com.iwdnb.gkgz.common.quota.MovingAverage;
import com.iwdnb.gkgz.common.utils.BigDecimalUtils;
import com.iwdnb.gkgz.common.utils.DateUtils;
import com.iwdnb.gkgz.common.utils.StockTrendUtils;
import com.iwdnb.gkgz.common.utils.StockUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import static com.iwdnb.gkgz.common.utils.StockUtils.getAveragePrice;

/**
 * 布林线从上轨直接跌穿中轨策略
 */
@Service
@Slf4j
public class BollingFallMiddleLineStockBackValidateService extends CommmonStockBackValidateService {

    private static final String STATEGY_CODE = "bollingFallMiddleLine";

    @Override
    public List<StrategyTradeDTO> queryBackValidateDateList(String code, String strategy,
        List<StockDayData> stockDayDataList,
        AddStrategyTradeStockDataRequest request) {
        int twentyPeriod = 20;
        int thirtyPeriod = 30;
        int sixtyPeriod = 60;
        MovingAverage.calculateEMA(stockDayDataList, 20);
        MovingAverage.calculateEMA(stockDayDataList, 30);
        MovingAverage.calculateEMA(stockDayDataList, 60);
        List<BollingerData> bollingerDataList = BollingerBands.calculateBollingerBands(stockDayDataList);
        List<String> dateList = new ArrayList<>();
        List<StrategyTradeDTO> strategyTradeDTOList = new ArrayList<>();
        for (int i = 0; i < bollingerDataList.size(); i++) {
            BollingerData bollingerData = bollingerDataList.get(i);
            String date = bollingerData.getDate();
            StockDayData data = StockUtils.getStockDayData(stockDayDataList, date);
            StockDayData tomorrowStockDayData = StockUtils.getTomorrowStockDayData(stockDayDataList, date);
            if (Objects.isNull(data) || Objects.isNull(tomorrowStockDayData)) {
                continue;
            }
            String tomorrowDate = tomorrowStockDayData.getDate();
            BollingerData tomorrowBollingerData = bollingerDataList.get(i + 1);
            //红绿灯，绿灯，跳过
            if (!RedGreenLightUtils.isAvailable(tomorrowDate)) {
                continue;
            }
            if (BigDecimalUtils.isLt(data.getClosePrice(), bollingerData.getHighBand())) {
                continue;
            }
            if (BigDecimalUtils.isGt(tomorrowStockDayData.getClosePrice(), tomorrowBollingerData.getMiddleBand())) {
                continue;
            }
            //一字跌停去掉
            if (BigDecimalUtils.isLt(tomorrowStockDayData.getRate(), new BigDecimal(-9))) {
                BigDecimal downRate = BigDecimalUtils.subStractAndDividePrecent(tomorrowStockDayData.getClosePrice(),
                    tomorrowStockDayData.getMinPrice()).abs();
                if (BigDecimalUtils.isLt(downRate, BigDecimal.ONE)) {
                    continue;
                }
            }
            //收盘价在60日均价下方，跳过
            BigDecimal sixtyAvg = getAveragePrice(data, 60);
            if (BigDecimalUtils.isLt(data.getOpenPrice(), sixtyAvg)) {
                continue;
            }
            //信号日比80个交易日前的最低价高100%，跳过
            BigDecimal beforeEightyLowPrice = StockUtils.getMinPriceBeforeDate(stockDayDataList, date, 80);
            BigDecimal beforeEightyLowRate = BigDecimalUtils.subStractAndDividePrecent(data.getClosePrice(),
                beforeEightyLowPrice);
            //log.debug("{}-{}-50日前的价差={}", code, date, beforeThirtyRate);
            if (BigDecimalUtils.isGt(beforeEightyLowRate, new BigDecimal(80))) {
                continue;
            }
            BigDecimal twentyAvg = getAveragePrice(data, twentyPeriod);
            BigDecimal thirtyAvg = getAveragePrice(data, thirtyPeriod);
            String twentyTrend = StockTrendUtils.getTrend(data, stockDayDataList, twentyPeriod);
            String thirtyTrend = StockTrendUtils.getTrend(data, stockDayDataList, thirtyPeriod);
            String sixtyTrend = StockTrendUtils.getTrend(data, stockDayDataList, sixtyPeriod);
            //20、30、60日线均向上，且价格依次排布
            Boolean trendFlag = RangeTypeEnums.UP.equalsCode(twentyTrend) && RangeTypeEnums.UP.equalsCode(thirtyTrend)
                && RangeTypeEnums.UP.equalsCode(sixtyTrend)
                && BigDecimalUtils.isGe(twentyAvg, thirtyAvg) && BigDecimalUtils.isGe(thirtyAvg, sixtyAvg);
            if (!trendFlag) {
                //log.debug("{}-{}趋势向下，跳过", code, date);
                continue;
            }
            if (!dateList.contains(tomorrowDate)) {
                dateList.add(tomorrowDate);
                StrategyTradeDTO strategyTradeDTO = new StrategyTradeDTO();
                strategyTradeDTO.setCode(code);
                strategyTradeDTO.setUuid(STATEGY_CODE);
                strategyTradeDTO.setBuyDate(DateUtil.parseDate(tomorrowDate));
                strategyTradeDTO.setBuyPrice(tomorrowStockDayData.getClosePrice());
                strategyTradeDTO.setStatus("buy");
                strategyTradeDTOList.add(strategyTradeDTO);
                //BigDecimal profit = caculateAfterDaysProfit(afterTwoDate, stockDayDataList, 5);
            }
        }
        return strategyTradeDTOList;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void doBackValidate(String code, String strategy, List<StockDayData> stockDayDataList,
        List<StrategyTradeDTO> strategyTradeDTOList) {
        List<String> dateList = strategyTradeDTOList.stream().map(o -> DateUtil.formatDate(o.getBuyDate())).collect(
            Collectors.toList());
        Date latestEndDate = DateUtil.parseDate(dateList.get(0));
        latestEndDate = DateUtil.offsetDay(latestEndDate, -1);
        for (StrategyTradeDTO strategyTradeDTO : strategyTradeDTOList) {
            Date d = strategyTradeDTO.getBuyDate();
            if (DateUtils.beforeOrEquals(d, latestEndDate)) {
                log.debug("{}-{}在上一个周期内,忽略", code, d);
                continue;
            }
            getTradeInfo(code, stockDayDataList, strategyTradeDTO);
            latestEndDate = strategyTradeDTO.getSellDate();
        }
    }

    private void getTradeInfo(String code, List<StockDayData> stockDayDataList, StrategyTradeDTO strategyTradeDTO) {
        String date = DateUtil.formatDate(strategyTradeDTO.getBuyDate());
        StockDayData buyDayData = StockUtils.getStockDayData(stockDayDataList, date);
        BigDecimal buyPrice = buyDayData.getClosePrice();
        List<StockDayData> subList = StockUtils.getStockDayDataListAfterDate(stockDayDataList, date, 5);
        if (CollectionUtils.isEmpty(subList) || subList.size() < 5) {
            return;
        }
        BigDecimal closeRate = null;
        String sellDate = null;
        String info = "";
        BigDecimal sellPrice = null;
        BigDecimal rate = closeRate;
        int holdIndex = 0;
        BigDecimal rangeMaxPrice = null;
        for (int i = 0; i < 1; i++) {
            StockDayData data = subList.get(i);
            BigDecimal closePrice = data.getClosePrice();
            BigDecimal range = BigDecimalUtils.subtract(closePrice, buyPrice);
            closeRate = BigDecimalUtils.divideToPrecent(range, buyPrice);
            sellDate = data.getDate();
            sellPrice = data.getClosePrice();
            holdIndex = i;
            rangeMaxPrice = data.getMaxPrice();
            BigDecimal upRange = data.getMaxPrice().subtract(buyPrice);
            BigDecimal upRate = BigDecimalUtils.divideToPrecent(upRange, buyPrice);
            BigDecimal openRange = data.getOpenPrice().subtract(buyPrice);
            BigDecimal openRate = BigDecimalUtils.divideToPrecent(openRange, buyPrice);
            rate = closeRate;
            String sellInfo = "收盘价卖出";
            log.debug("{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", code, data.getDate(), sellInfo, rate, openRate,
                closeRate, upRate);
            info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                + ",最高点收益=" + upRate;
            break;

        }
        strategyTradeDTO.setHoldDay(holdIndex + 1);
        strategyTradeDTO.setSellDate(DateUtil.parseDate(sellDate));
        strategyTradeDTO.setSellPrice(sellPrice);
        strategyTradeDTO.setProfitRate(rate);
        strategyTradeDTO.setRangeMaxPrice(rangeMaxPrice);
        strategyTradeDTO.setRealtimeRate(BigDecimalUtils.subStractAndDividePrecent(rangeMaxPrice, buyPrice));
        strategyTradeDTO.setStrategyDescription(info);
        strategyTradeDTO.setStatus("sell");
        strategyTradeDTO.setWinFlag(BigDecimalUtils.isGt(rate, BigDecimal.ZERO) ? "y" : "n");
    }

}
